#ifndef _WX_COMBOCONTROL_H_BASE_
#define _WX_COMBOCONTROL_H_BASE_

#include "wx/defs.h"

#if wxUSE_COMBOCTRL

#include "wx/control.h"
#include "wx/renderer.h" // this is needed for wxCONTROL_XXX flags
#include "wx/bitmap.h" // wxBitmap used by-value

class wxTextCtrl;
class wxComboPopup;

//
// New window styles for wxComboCtrlBase
//
enum {
  // Double-clicking a read-only combo triggers call to popup's OnComboPopup.
  // In wxOwnerDrawnComboBox, for instance, it cycles item.
  wxCC_SPECIAL_DCLICK             = 0x0100,

  // Dropbutton acts like standard push button.
  wxCC_STD_BUTTON                 = 0x0200
};


// wxComboCtrl internal flags
enum {
  // First those that can be passed to Customize.
  // It is Windows style for all flags to be clear.

  // Button is preferred outside the border (GTK style)
  wxCC_BUTTON_OUTSIDE_BORDER      = 0x0001,
  // Show popup on mouse up instead of mouse down (which is the Windows style)
  wxCC_POPUP_ON_MOUSE_UP          = 0x0002,
  // All text is not automatically selected on click
  wxCC_NO_TEXT_AUTO_SELECT        = 0x0004,
  // Drop-button stays down as long as popup is displayed.
  wxCC_BUTTON_STAYS_DOWN          = 0x0008,
  // Drop-button covers the entire control.
  wxCC_FULL_BUTTON                = 0x0010,
  // Drop-button goes over the custom-border (used under WinVista).
  wxCC_BUTTON_COVERS_BORDER       = 0x0020,

  // Internal use: signals creation is complete
  wxCC_IFLAG_CREATED              = 0x0100,
  // Internal use: really put button outside
  wxCC_IFLAG_BUTTON_OUTSIDE       = 0x0200,
  // Internal use: SetTextIndent has been called
  wxCC_IFLAG_INDENT_SET           = 0x0400,
  // Internal use: Set wxTAB_TRAVERSAL to parent when popup is dismissed
  wxCC_IFLAG_PARENT_TAB_TRAVERSAL = 0x0800,
  // Internal use: Secondary popup window type should be used (if available).
  wxCC_IFLAG_USE_ALT_POPUP        = 0x1000,
  // Internal use: Skip popup animation.
  wxCC_IFLAG_DISABLE_POPUP_ANIM   = 0x2000,
  // Internal use: Drop-button is a bitmap button or has non-default size
  // (but can still be on either side of the control), regardless whether
  // specified by the platform or the application.
  wxCC_IFLAG_HAS_NONSTANDARD_BUTTON   = 0x4000
};


// Flags used by PreprocessMouseEvent and HandleButtonMouseEvent
enum {
  wxCC_MF_ON_BUTTON               =   0x0001, // cursor is on dropbutton area
  wxCC_MF_ON_CLICK_AREA           =   0x0002  // cursor is on dropbutton or other area
                                      // that can be clicked to show the popup.
};


// Namespace for wxComboCtrl feature flags
struct wxComboCtrlFeatures {
  enum {
    MovableButton       = 0x0001, // Button can be on either side of control
    BitmapButton        = 0x0002, // Button may be replaced with bitmap
    ButtonSpacing       = 0x0004, // Button can have spacing from the edge
    // of the control
    TextIndent          = 0x0008, // SetTextIndent can be used
    PaintControl        = 0x0010, // Combo control itself can be custom painted
    PaintWritable       = 0x0020, // A variable-width area in front of writable
    // combo control's textctrl can be custom
    // painted
    Borderless          = 0x0040, // wxNO_BORDER window style works
    All                 = MovableButton | BitmapButton |
                          ButtonSpacing | TextIndent |
                          PaintControl | PaintWritable |
                          Borderless
  };
};

class wxComboCtrlBase : public wxControl {
    friend class wxComboPopup;
  public:
    wxComboCtrlBase() : wxControl() { Init(); }
    bool Create( wxWindow *parent,wxWindowID id,const wxString& value,const wxPoint& pos,
                 const wxSize& size,long style,const wxValidator& validator,const wxString& name );

    virtual ~wxComboCtrlBase();
    virtual void ShowPopup();
    virtual void HidePopup();
    virtual void OnButtonClick();
    bool IsPopupShown() const { return m_popupWinState == Visible; }
    void SetPopupControl( wxComboPopup* popup ) {
      DoSetPopupControl( popup );
    }
    wxComboPopup* GetPopupControl() {
      EnsurePopupControl();
      return m_popupInterface;
    }
    wxWindow *GetPopupWindow() const { return m_winPopup; }
    wxTextCtrl *GetTextCtrl() const { return m_text; }
    wxWindow *GetButton() const { return m_btn; }
    virtual bool Enable( bool enable = true );
    virtual bool Show( bool show = true );
    virtual bool SetFont( const wxFont& font );
    #if wxUSE_VALIDATORS
    virtual void SetValidator( const wxValidator &validator );
    virtual wxValidator *GetValidator();
    #endif // wxUSE_VALIDATORS

    virtual wxString GetValue() const;
    virtual void SetValue( const wxString& value );
    virtual void Copy();
    virtual void Cut();
    virtual void Paste();
    virtual void SetInsertionPoint( long pos );
    virtual void SetInsertionPointEnd();
    virtual long GetInsertionPoint() const;
    virtual long GetLastPosition() const;
    virtual void Replace( long from, long to, const wxString& value );
    virtual void Remove( long from, long to );
    virtual void SetSelection( long from, long to );
    virtual void Undo();
    void SetText( const wxString& value );
    void SetValueWithEvent( const wxString& value, bool withEvent = true );
    void SetPopupMinWidth( int width ) {
      m_widthMinPopup = width;
    }

    void SetPopupMaxHeight( int height ) {
      m_heightPopup = height;
    }

    void SetPopupExtents( int extLeft, int extRight ) {
      m_extLeft = extLeft;
      m_extRight = extRight;
    }

    void SetCustomPaintWidth( int width );
    int GetCustomPaintWidth() const { return m_widthCustomPaint; }

    // Set side of the control to which the popup will align itself.
    // Valid values are wxLEFT, wxRIGHT and 0. The default value 0 wmeans
    // that the side of the button will be used.
    void SetPopupAnchor( int anchorSide ) {
      m_anchorSide = anchorSide;
    }

    void SetButtonPosition( int width = -1,
                            int height = -1,
                            int side = wxRIGHT,
                            int spacingX = 0 );

    wxSize GetButtonSize();
    void SetButtonBitmaps( const wxBitmap& bmpNormal,
                           bool pushButtonBg = false,
                           const wxBitmap& bmpPressed = wxNullBitmap,
                           const wxBitmap& bmpHover = wxNullBitmap,
                           const wxBitmap& bmpDisabled = wxNullBitmap );
    void SetTextIndent( int indent );
    wxCoord GetTextIndent() const {
      return m_absIndent;
    }
    const wxRect& GetTextRect() const {
      return m_tcArea;
    }
    void UseAltPopupWindow( bool enable = true ) {
      wxASSERT_MSG( !m_winPopup,
                    wxT( "call this only before SetPopupControl" ) );
      if( enable ) {
        m_iFlags |= wxCC_IFLAG_USE_ALT_POPUP;
      } else
      { m_iFlags &= ~wxCC_IFLAG_USE_ALT_POPUP; }
    }
    void EnablePopupAnimation( bool enable = true ) {
      if( enable ) {
        m_iFlags &= ~wxCC_IFLAG_DISABLE_POPUP_ANIM;
      } else
      { m_iFlags |= wxCC_IFLAG_DISABLE_POPUP_ANIM; }
    }
    virtual bool IsKeyPopupToggle( const wxKeyEvent& event ) const = 0;
    virtual void PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const;
    bool ShouldDrawFocus() const {
      const wxWindow* curFocus = FindFocus();
      return ( IsPopupWindowState( Hidden ) &&
               ( curFocus == m_mainCtrlWnd || ( m_btn && curFocus == m_btn ) ) &&
               ( m_windowStyle & wxCB_READONLY ) );
    }
    const wxBitmap& GetBitmapNormal() const { return m_bmpNormal; }
    const wxBitmap& GetBitmapPressed() const { return m_bmpPressed; }
    const wxBitmap& GetBitmapHover() const { return m_bmpHover; }
    const wxBitmap& GetBitmapDisabled() const { return m_bmpDisabled; }
    wxUint32 GetInternalFlags() const { return m_iFlags; }
    bool IsCreated() const { return m_iFlags & wxCC_IFLAG_CREATED ? true : false; }
    void OnPopupDismiss();

    enum {
      Hidden       = 0,
      Animating    = 2,
      Visible      = 3
    };

    bool IsPopupWindowState( int state ) const { return ( state == m_popupWinState ) ? true : false; }

    wxByte GetPopupWindowState() const { return m_popupWinState; }

    // Set value returned by GetMainWindowOfCompositeControl
    void SetCtrlMainWnd( wxWindow* wnd ) { m_mainCtrlWnd = wnd; }

  protected:

    //
    // Override these for customization purposes
    //

    // called from wxSizeEvent handler
    virtual void OnResize() = 0;

    // Return native text identation (for pure text, not textctrl)
    virtual wxCoord GetNativeTextIndent() const;

    // Called in syscolourchanged handler and base create
    virtual void OnThemeChange();

    // Creates wxTextCtrl.
    //   extraStyle: Extra style parameters
    void CreateTextCtrl( int extraStyle, const wxValidator& validator );

    // Installs standard input handler to combo (and optionally to the textctrl)
    void InstallInputHandlers();

    // flags for DrawButton()
    enum {
      Draw_PaintBg = 1,
      Draw_BitmapOnly  = 2
    };

    // Draws dropbutton. Using wxRenderer or bitmaps, as appropriate.
    void DrawButton( wxDC& dc, const wxRect& rect, int flags = Draw_PaintBg );

    // Call if cursor is on button area or mouse is captured for the button.
    //bool HandleButtonMouseEvent( wxMouseEvent& event, bool isInside );
    bool HandleButtonMouseEvent( wxMouseEvent& event, int flags );

    // returns true if event was consumed or filtered (event type is also set to 0 in this case)
    bool PreprocessMouseEvent( wxMouseEvent& event, int flags );
    void HandleNormalMouseEvent( wxMouseEvent& event );

    // Creates popup window, calls interface->Create(), etc
    void CreatePopup();

    // Destroy popup window and all related constructs
    void DestroyPopup();

    // override the base class virtuals involved in geometry calculations
    virtual wxSize DoGetBestSize() const;

    // NULL popup can be used to indicate default in a derived class
    virtual void DoSetPopupControl( wxComboPopup* popup );

    // ensures there is atleast the default popup
    void EnsurePopupControl();

    // Recalculates button and textctrl areas. Called when size or button setup change.
    //   btnWidth: default/calculated width of the dropbutton. 0 means unchanged,
    //             just recalculate.
    void CalculateAreas( int btnWidth = 0 );

    // Standard textctrl positioning routine. Just give it platform-dependant
    // textctrl coordinate adjustment.
    void PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust );

    // event handlers
    void OnSizeEvent( wxSizeEvent& event );
    void OnFocusEvent( wxFocusEvent& event );
    void OnIdleEvent( wxIdleEvent& event );
    void OnTextCtrlEvent( wxCommandEvent& event );
    void OnSysColourChanged( wxSysColourChangedEvent& event );
    void OnKeyEvent( wxKeyEvent& event );

    // Set customization flags (directs how wxComboCtrlBase helpers behave)
    void Customize( wxUint32 flags ) { m_iFlags |= flags; }

    // Dispatches size event and refreshes
    void RecalcAndRefresh();

    // Flags for DoShowPopup and AnimateShow
    enum {
      ShowBelow       = 0x0000,  // Showing popup below the control
      ShowAbove       = 0x0001,  // Showing popup above the control
      CanDeferShow    = 0x0002  // Can only return true from AnimateShow if this is set
    };

    // Shows and positions the popup.
    virtual void DoShowPopup( const wxRect& rect, int flags );
    virtual bool AnimateShow( const wxRect& rect, int flags );

    #if wxUSE_TOOLTIPS
    virtual void DoSetToolTip( wxToolTip *tip );
    #endif

    virtual wxWindow *GetMainWindowOfCompositeControl() { return m_mainCtrlWnd; }

    // This is used when m_text is hidden (readonly).
    wxString                m_valueString;

    // the text control and button we show all the time
    wxTextCtrl*             m_text;
    wxWindow*               m_btn;

    // wxPopupWindow or similar containing the window managed by the interface.
    wxWindow*               m_winPopup;

    // the popup control/panel
    wxWindow*               m_popup;

    // popup interface
    wxComboPopup*           m_popupInterface;

    // this is input etc. handler for the text control
    wxEvtHandler*           m_textEvtHandler;

    // this is for the top level window
    wxEvtHandler*           m_toplevEvtHandler;

    // this is for the control in popup
    wxEvtHandler*           m_popupExtraHandler;

    // this is for the popup window
    wxEvtHandler*           m_popupWinEvtHandler;

    // main (ie. topmost) window of a composite control (default = this)
    wxWindow*               m_mainCtrlWnd;

    // used to prevent immediate re-popupping incase closed popup
    // by clicking on the combo control (needed because of inconsistent
    // transient implementation across platforms).
    wxLongLong              m_timeCanAcceptClick;

    // how much popup should expand to the left/right of the control
    wxCoord                 m_extLeft;
    wxCoord                 m_extRight;

    // minimum popup width
    wxCoord                 m_widthMinPopup;

    // preferred popup height
    wxCoord                 m_heightPopup;

    // how much of writable combo is custom-paint by callback?
    // also used to indicate area that is not covered by "blue"
    // selection indicator.
    wxCoord                 m_widthCustomPaint;

    // absolute text indentation, in pixels
    wxCoord                 m_absIndent;

    // side on which the popup is aligned
    int                     m_anchorSide;

    // Width of the "fake" border
    wxCoord                 m_widthCustomBorder;

    // The button and textctrl click/paint areas
    wxRect                  m_tcArea;
    wxRect                  m_btnArea;

    // current button state (uses renderer flags)
    int                     m_btnState;

    // button position
    int                     m_btnWid;
    int                     m_btnHei;
    int                     m_btnSide;
    int                     m_btnSpacingX;

    // last default button width
    int                     m_btnWidDefault;

    // custom dropbutton bitmaps
    wxBitmap                m_bmpNormal;
    wxBitmap                m_bmpPressed;
    wxBitmap                m_bmpHover;
    wxBitmap                m_bmpDisabled;

    // area used by the button
    wxSize                  m_btnSize;

    // platform-dependant customization and other flags
    wxUint32                m_iFlags;

    // draw blank button background under bitmap?
    bool                    m_blankButtonBg;

    // is the popup window currenty shown?
    wxByte                  m_popupWinState;

    // should the focus be reset to the textctrl in idle time?
    bool                    m_resetFocus;

  private:
    void Init();

    wxByte                  m_ignoreEvtText;  // Number of next EVT_TEXTs to ignore

    // Is popup window wxPopupTransientWindow, wxPopupWindow or wxDialog?
    wxByte                  m_popupWinType;

    DECLARE_EVENT_TABLE()

    DECLARE_ABSTRACT_CLASS( wxComboCtrlBase )
};

enum {
  wxCP_IFLAG_CREATED      = 0x0001 // Set by wxComboCtrlBase after Create is called
};


class wxComboPopup {
    friend class wxComboCtrlBase;
  public:
    wxComboPopup() {
      m_combo = ( wxComboCtrlBase* ) NULL;
      m_iFlags = 0;
    }

    virtual void Init() { }

    virtual ~wxComboPopup();

    // Create the popup child control.
    // Return true for success.
    virtual bool Create( wxWindow* parent ) = 0;

    // We must have an associated control which is subclassed by the combobox.
    virtual wxWindow *GetControl() = 0;

    // Called immediately after the popup is shown
    virtual void OnPopup();

    // Called when popup is dismissed
    virtual void OnDismiss();

    // Called just prior to displaying popup.
    // Default implementation does nothing.
    virtual void SetStringValue( const wxString& value );

    // Gets displayed string representation of the value.
    virtual wxString GetStringValue() const = 0;
    virtual void PaintComboControl( wxDC& dc, const wxRect& rect );
    virtual void OnComboKeyEvent( wxKeyEvent& event );
    virtual void OnComboDoubleClick();
    virtual wxSize GetAdjustedSize( int minWidth, int prefHeight, int maxHeight );
    virtual bool LazyCreate();

    //
    // Utilies
    //

    // Hides the popup
    void Dismiss();

    // Returns true if Create has been called.
    bool IsCreated() const {
      return ( m_iFlags & wxCP_IFLAG_CREATED ) ? true : false;
    }
    static void DefaultPaintComboControl( wxComboCtrlBase* combo,wxDC& dc,const wxRect& rect );

  protected:
    wxComboCtrlBase* m_combo;
    wxUint32            m_iFlags;

  private:
    // Called in wxComboCtrlBase::SetPopupControl
    void InitBase( wxComboCtrlBase *combo ) {
      m_combo = combo;
    }
};

#include "wx/generic/combo.h"

#endif // wxUSE_COMBOCTRL

#endif
